#region File Description
//-----------------------------------------------------------------------------
// SpriteFontControl.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Windows.Forms;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml;
using SharedCongkak;
using QuickGraph;
#endregion

using Path = SharedCongkak.Path;

namespace CongkakEditor
{
    /// <summary>
    /// Example control inherits from GraphicsDeviceControl, which allows it to
    /// render using a GraphicsDevice. This control shows how to use ContentManager
    /// inside a WinForms application. It loads a SpriteFont object through the
    /// ContentManager, then uses a SpriteBatch to draw text. The control is not
    /// animated, so it only redraws itself in response to WinForms paint messages.
    /// </summary>
    class LevelControl : GraphicsDeviceControl
    {
        ContentManager content;
        SpriteBatch spriteBatch;
        SpriteFont font;

        LevelData levelData = new LevelData();
        AdjacencyGraph<AbstractHole, SharedCongkak.Path> level;
        List<SharedCongkak.Path> pathList = new List<SharedCongkak.Path>();
        AbstractHole highlightedHole, selectedHole, sourceHole;


        GameTime gameTime;
        Stopwatch elapsedTime = new Stopwatch();
        Stopwatch totalTime = new Stopwatch();

        // Timer to keep track of refreshes
        Timer timer;

        private System.Drawing.Point prevMousePos;

        private AbstractHole HighlightedHole
        {
            get { return highlightedHole; }
            set { highlightedHole = value; OnHighlightedHoleChange(value, null); }
        }

        Vector2 creationPos = new Vector2(400, 400);

        public event EventHandler OnHoleSelect;
        public event EventHandler<HoleEventArgs> OnSeedAddedToHole;
        public event EventHandler<HoleEventArgs> OnHighlightedHoleChange;
        public event EventHandler OnLevelChange;
 

        //public AdjacencyGraph<AbstractHole, SharedCongkak.Path> Level
        //{
        //    set { level = value; }
        //    get { return level; }
        //}

        /// <summary>
        /// Initializes the control, creating the ContentManager
        /// and using it to load a SpriteFont.
        /// </summary>
        protected override void Initialize()
        {
            content = new ContentManager(Services, "Content");

            content.RootDirectory = "C:\\Users\\Khalid\\Documents\\Visual Studio 2008\\Projects\\Congkak\\Congkak\\bin\\x86\\Debug\\Content";
            spriteBatch = new SpriteBatch(GraphicsDevice);

            font = content.Load<SpriteFont>("Arial");
            Path.LoadContent(content);
            //levelData = content.Load<LevelData>("LevelData/XNAlevel");
            //level = levelData.ConvertToQuickGraph();
            level = new AdjacencyGraph<AbstractHole, Path>();
            level.EdgeAdded += (Path edge) =>
            {
                edge.Source.NextEdges.Add(edge);
                edge.Target.PrevEdges.Add(edge);
                edge.CreatePath();
            };

            level.EdgeRemoved += (edge) =>
                {
                    edge.Source.NextEdges.Remove(edge);
                    edge.Target.PrevEdges.Remove(edge);
                };
            timer = new Timer();
            // Lock framerate to 40 so we can keep performance up
            timer.Interval = (int)((1f / 40f) * 1000);

            // Hook timer's tick so we can refresh the view on cue
            timer.Tick += new System.EventHandler(timer_Tick);
            timer.Start();

            totalTime.Start();
            //Application.Idle += delegate { base.Invalidate(); };
        }

        void timer_Tick(object sender, EventArgs e)
        {
            // Invalidate everything so the whole control refreshes
            this.Invalidate();

            // Force the view update
            this.Update();

        }


        /// <summary>
        /// Disposes the control, unloading the ContentManager.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                content.Unload();
            }

            base.Dispose(disposing);
        }

        private void UpdateGameTime()
        {
            // Recreate the GameTime with the current values
            gameTime = new GameTime(totalTime.Elapsed, totalTime.Elapsed, elapsedTime.Elapsed, elapsedTime.Elapsed);

            // Restart the elapsed timer that keeps track of time between frames
            elapsedTime.Reset();
            elapsedTime.Start();
        }

        private void Update(GameTime gameTime)
        {
            foreach (SharedCongkak.Path path in level.Edges)
            {
                path.Update(gameTime);
            }
        }



        /// <summary>
        /// Draws the control, using SpriteBatch and SpriteFont.
        /// </summary>
        protected override void Draw()
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            UpdateGameTime();
            Update(gameTime);

            UpdateGameTime();
            spriteBatch.Begin();
            foreach (var hole in level.Vertices)
            {
                hole.Draw(spriteBatch);
            }

            foreach (var path in level.Edges)
            {
                path.Draw(spriteBatch);
            }
            spriteBatch.End();
        }

        public AbstractHole CreateNewHole()
        {
            Hole newHole = new Hole();
            newHole.LoadContent(content);
            newHole.Position = creationPos;
            level.AddVertex(newHole);
            return newHole;
        }

        public AbstractHole CreateNewStore()
        {
            Store newStore = new Store();
            newStore.LoadContent(content);
            newStore.Position = creationPos;
            newStore.OnEnter += HighlightHole;
            newStore.OnSeedAdded += (_sender, _args) => OnSeedAddedToHole(_sender, _args);
            newStore.OnSelect += SelectHole;
            level.AddVertex(newStore);
            return newStore;
        }

        public AbstractHole GetHole(Point position)
        {
            foreach (var hole in level.Vertices)
            {
                if (hole.ContainsPoint(position))
                {
                    return hole;
                }
            }
            return null;
        }

        private void HighlightHole(Object hole, EventArgs eventArg)
        {
            highlightedHole.Highlight = false;
            highlightedHole = hole as AbstractHole;
            highlightedHole.Highlight = true;
        }

        private void SelectHole(Object hole, EventArgs eventArg)
        {
            OnHoleSelect(hole, eventArg);

        }

        private void AddPath(AbstractHole source, AbstractHole target)
        {
            if (source == target || source == null || target == null)
                return;
            Path path = new Path(source, target);
            level.AddEdge(path);
        }

        protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
        {
          
            if (selectedHole != null)
            {
                Point delta = new Point(e.X - prevMousePos.X, e.Y - prevMousePos.Y);
                selectedHole.Center += new Vector2(delta.X, delta.Y);
                prevMousePos = e.Location;
            }
            else
            {
                AbstractHole hole = GetHole(new Point(e.X, e.Y));
                if (hole != null)
                {
                    this.Cursor = Cursors.SizeAll;
                }
                else 
                    this.Cursor = Cursors.Default;
            }
            base.OnMouseMove(e);

        }

        protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
        {
            
            AbstractHole hole = GetHole(new Point(e.X, e.Y));
            if (hole == null) return;

            if (e.Button == MouseButtons.Left)
            {
               
                if (e.Clicks == 2)
                {
                    hole.StartPathEffect();
                }
                else if (e.Clicks == 1)
                {
                    prevMousePos = e.Location;
                    selectedHole = hole;
                    HighlightedHole = hole;
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                sourceHole = hole;
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {

                AbstractHole hole = GetHole(new Point(e.X, e.Y));
                if (sourceHole == hole && sourceHole.NextEdges.Count > 0)
                    level.RemoveEdge(sourceHole.NextEdges.Last());
                else
                    AddPath(sourceHole, hole);
            }
            OnHighlightedHoleChange(HighlightedHole, null);
            selectedHole = null;
            base.OnMouseUp(e);
        }

        public void Serialize(String fileLocation)
        {
            levelData.FromQuickGraph(level);
            using (XmlWriter write = XmlWriter.Create(fileLocation))
                IntermediateSerializer.Serialize<LevelData>(write, levelData, null);
        }

        public void Deserialize(String assetName, ContentManager contentLevel)
        {
            levelData = contentLevel.Load<LevelData>(assetName);
            level = levelData.ConvertToQuickGraph();
        }
    }
}
